﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI.WebControls;
using System.Xml;
using JQuery.WebKit.Common.ActiveDirectory;
using JQuery.WebKit.WebCommon.Templates;

namespace JQuery.WebKit.WebCommon.Security
{
    public class JSecurityPrincipal : ISecurityPrincipal
    {
        public bool IsAuthenticated
        {
            get { return SecurityInfo != null; }
        }

        public UserInfo SecurityInfo
        {
            get;
            set;
        }

        public string CurrentRole
        {
            get;
            set;
        }

        public List<string> Roles
        {
            get;
            set;
        }

        public string AccountName
        {
            get { return SecurityInfo != null ? SecurityInfo.Name : string.Empty; }
        }

        public string UserName
        {
            get { return SecurityInfo != null ? SecurityInfo.DisplayName : string.Empty; }
        }

        public string Email
        {
            get { return SecurityInfo != null ? SecurityInfo.EmailAddress : string.Empty; }
        }

        public JSecurityPrincipal()
        {
            Roles = new List<string>();
        }

        private bool IsInSecurityContext()
        {
            return IsInSecurityContext(GetBasePath());
        }

        private bool IsInSecurityContext(string name)
        {
            string data = Template.Load("/App_Data/SecurityContext.xml");
            if (string.IsNullOrEmpty(data))
            {
                return true;
            }

            XmlDataSource dataSource = new XmlDataSource();
            //dataSource.Data.DataFile = "~/App_Data/SecurityContext.xml";
            dataSource.Data = data;
            dataSource.ID = "securityContextDS";

            XmlDocument xdoc = dataSource.GetXmlDocument();
            XmlElement root = xdoc.DocumentElement;

            foreach (XmlNode rt in root.ChildNodes)
            {
                if (rt.NodeType != XmlNodeType.Element)
                {
                    continue;
                }
                string contextName = rt.Attributes["Name"] != null ? rt.Attributes["Name"].Value : null;

                if (!string.IsNullOrEmpty(contextName) && name.ToLower() == contextName.ToLower())
                {
                    return IsInRole(rt, Roles);
                }
            }

            return false;
        }

        private bool IsInSecurityContext(Uri url)
        {
            string data = Template.Load("/App_Data/SecurityContext.xml");
            if (string.IsNullOrEmpty(data))
            {
                return true;
            }

            XmlDataSource dataSource = new XmlDataSource();
            //dataSource.Data.DataFile = "~/App_Data/SecurityContext.xml";
            dataSource.Data = data;
            dataSource.ID = "securityContextDS";

            XmlDocument xdoc = dataSource.GetXmlDocument();
            XmlElement root = xdoc.DocumentElement;
            string path = HttpContext.Current.Server.MapPath(GetLocalPath(url));
            foreach (XmlNode rt in root.ChildNodes)
            {
                if (rt.NodeType != XmlNodeType.Element)
                {
                    continue;
                }
                string contextPath = rt.Attributes["Path"] != null ? rt.Attributes["Path"].Value : null;
                contextPath = HttpContext.Current.Server.MapPath(contextPath);
                if (!string.IsNullOrEmpty(contextPath) && path.ToLower().EndsWith(contextPath.ToLower()))
                {
                    return IsInRole(rt, Roles);
                }
            }

            return false;
        }

        private static bool IsInRole(XmlNode node, List<string> currentRoles)
        {
            string strRoles = (node.Attributes["Roles"] != null) ? node.Attributes["Roles"].Value : string.Empty;
            if (string.IsNullOrEmpty(strRoles))
            {
                //show node if no roles are defined
                return true;
            }

            //case insensitive role names
            string[] roles = strRoles.Split(',');
            foreach (string role in roles)
            {
                if (currentRoles.Contains(role.Trim()))
                {
                    return true;
                }
            }

            return false;
        }

        public bool CheckName(string name)
        {
            return IsInSecurityContext(name);
        }

        public bool CheckName(Uri url)
        {
            return IsInSecurityContext(url);
        }

        internal static string GetBasePath()
        {
            string path = string.Format("{0}://{1}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority);
            int segmentsCount = HttpContext.Current.Request.Url.Segments.Length;
            if (HttpContext.Current.Request.Url.Segments.Length >= 1)
            {
                for (int i = 0; i < segmentsCount; i++)
                {
                    path += HttpContext.Current.Request.Url.Segments[i];
                    if (path.EndsWith(".aspx") ||
                        path.EndsWith(".aspx/") ||
                        path.EndsWith(".asmx") ||
                        path.EndsWith(".asmx/"))
                    {
                        break;
                    }
                }
            }
            return path.EndsWith("/") ? path.Substring(0, path.Length - 1) : path;
        }

        internal static string GetLocalPath(Uri url)
        {
            string path = string.Empty;
            int segmentsCount = url.Segments.Length;
            if (url.Segments.Length >= 1)
            {
                for (int i = 0; i < segmentsCount; i++)
                {
                    path += url.Segments[i];
                    if (path.EndsWith(".aspx") ||
                        path.EndsWith(".aspx/") ||
                        path.EndsWith(".asmx") ||
                        path.EndsWith(".asmx/"))
                    {
                        break;
                    }
                }
            }
            return path.EndsWith("/") ? path.Substring(0, path.Length - 1) : path;
        }
    }
}
